
import { reactive } from 'vue'
import {Buffer} from 'buffer'
import { useCookies } from "vue3-cookies";

// console.log('xx=', Buffer);
window.Buffer = Buffer

// import WalletConnectProvider from "@walletconnect/web3-provider";
import WalletConnect from "@walletconnect/client";
import QRCodeModal from "@walletconnect/qrcode-modal";

let t;
function setDappLocate(tt) {
    t = tt
}

var abi = [
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "owner",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "spender",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "value",
                "type": "uint256"
            }
        ],
        "name": "Approval",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "from",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "to",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "value",
                "type": "uint256"
            }
        ],
        "name": "Transfer",
        "type": "event"
    },
    {
        "constant": false,
        "inputs": [
            {
                "internalType": "address",
                "name": "spender",
                "type": "address"
            },
            {
                "internalType": "uint256",
                "name": "value",
                "type": "uint256"
            }
        ],
        "name": "approve",
        "outputs": [
            {
                "internalType": "bool",
                "name": "",
                "type": "bool"
            }
        ],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "constant": false,
        "inputs": [
            {
                "internalType": "address",
                "name": "spender",
                "type": "address"
            },
            {
                "internalType": "uint256",
                "name": "subtractedValue",
                "type": "uint256"
            }
        ],
        "name": "decreaseAllowance",
        "outputs": [
            {
                "internalType": "bool",
                "name": "",
                "type": "bool"
            }
        ],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "constant": false,
        "inputs": [
            {
                "internalType": "address",
                "name": "spender",
                "type": "address"
            },
            {
                "internalType": "uint256",
                "name": "addedValue",
                "type": "uint256"
            }
        ],
        "name": "increaseAllowance",
        "outputs": [
            {
                "internalType": "bool",
                "name": "",
                "type": "bool"
            }
        ],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "constant": false,
        "inputs": [
            {
                "internalType": "address",
                "name": "recipient",
                "type": "address"
            },
            {
                "internalType": "uint256",
                "name": "amount",
                "type": "uint256"
            }
        ],
        "name": "transfer",
        "outputs": [
            {
                "internalType": "bool",
                "name": "",
                "type": "bool"
            }
        ],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "constant": false,
        "inputs": [
            {
                "internalType": "address",
                "name": "sender",
                "type": "address"
            },
            {
                "internalType": "address",
                "name": "recipient",
                "type": "address"
            },
            {
                "internalType": "uint256",
                "name": "amount",
                "type": "uint256"
            }
        ],
        "name": "transferFrom",
        "outputs": [
            {
                "internalType": "bool",
                "name": "",
                "type": "bool"
            }
        ],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "constructor"
    },
    {
        "constant": true,
        "inputs": [
            {
                "internalType": "address",
                "name": "owner",
                "type": "address"
            },
            {
                "internalType": "address",
                "name": "spender",
                "type": "address"
            }
        ],
        "name": "allowance",
        "outputs": [
            {
                "internalType": "uint256",
                "name": "",
                "type": "uint256"
            }
        ],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    },
    {
        "constant": true,
        "inputs": [
            {
                "internalType": "address",
                "name": "account",
                "type": "address"
            }
        ],
        "name": "balanceOf",
        "outputs": [
            {
                "internalType": "uint256",
                "name": "",
                "type": "uint256"
            }
        ],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    },
    {
        "constant": true,
        "inputs": [],
        "name": "decimals",
        "outputs": [
            {
                "internalType": "uint8",
                "name": "",
                "type": "uint8"
            }
        ],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    },
    {
        "constant": true,
        "inputs": [],
        "name": "name",
        "outputs": [
            {
                "internalType": "string",
                "name": "",
                "type": "string"
            }
        ],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    },
    {
        "constant": true,
        "inputs": [],
        "name": "symbol",
        "outputs": [
            {
                "internalType": "string",
                "name": "",
                "type": "string"
            }
        ],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    },
    {
        "constant": true,
        "inputs": [],
        "name": "totalSupply",
        "outputs": [
            {
                "internalType": "uint256",
                "name": "",
                "type": "uint256"
            }
        ],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    }
]

const chainId = "0x38"  // bsc mainnet
// const chainId = "0x61"  // nsc testnet

var web3 = {}

if (__DAPP__) {
    var web3Url = chainId === "0x38" ? "https://nodes.pancakeswap.com/" : "https://data-seed-prebsc-1-s1.binance.org:8545/"
    console.log('use web3', chainId, web3Url);
    web3 = new Web3(
        // "http://127.0.0.1:8545" //
        web3Url
    );
}

var address = '';

const state = reactive({
    active: false,
    loaded: undefined,
    address: '',
    connected: false,
    connectType: '',    // metamask|connect|http
    token: '',
});

const { cookies } = useCookies();

if (!__DAPP__) {
    var _token = cookies.get('token3')
    if (_token && _token.length === 32) {
        state.token = _token
        state.connectType = 'http'
        state.connected = true
    }
}

const listeners = []

function addConnectListener(listner) {
    listeners.push(listner)
}

const addNetwork = (params) =>
    window.ethereum.request({ method: 'wallet_addEthereumChain', params })
        .then(() => {
            // setLog([...log, `Switched to ${params[0].chainName} (${parseInt(params[0].chainId)})`])
            // setChainId(parseInt(params[0].chainId))
            console.log('set ok ?');
        })
        .catch((error) => console.error(`Error: ${error.message}`))


const bridge = "https://bridge.walletconnect.org";
// const bridge = "http://192.168.2.188:7000";
// create new connector
let connector = {
    on: () => {},
    killSession: () => {},
};

if (__DAPP__) {
    connector = new WalletConnect({ bridge, qrcodeModal: QRCodeModal, qrcodeModalOptions: {
            mobileLinks: [
                'argent',
                'imtoken',
                'trust',
                'metamask',
                'tokenpocket',
                'bitpie',
                'math',
                'safepal',
                'pillar',
                // 'equalwallet',
                // 'coolwallet',
                // 'xwallet',
                // 'atomic',
                // 'cosmostation',
                // 'infinity',
                'coin98',
                'bitkeep',
                'bitpay',
            ]
        } });

    connector.on("connect", (error, payload) => {
        if (error) {
            throw error;
        }

        // Get provided accounts and chainId
        const { accounts, chainId } = payload.params[0];

        // alert(chainId + '-' + JSON.stringify(accounts))
        state.address = accounts[0]
        state.connected = true
        state.connectType = 'connect'
        listeners.map(fn => fn())

        // console.log('connect==', accounts, chainId);
    });

    connector.on('disconnect', (error, payload) => {
        console.log('disconnect')
        state.address=''
        state.connected = false
    })

}

async function disconnect() {
    console.log('disconnect..')
    state.connected = false;
    state.address = ''
    state.token = ''
    cookies.remove('token3')
    connector.killSession()
}

async function connectMetamask() {
    let _chainId = await ethereum.request({method: 'eth_chainId'})
    console.log('chainId=', _chainId);
    if (_chainId !== chainId) {
        await addNetwork([
            {
                chainId: '0x38',
                chainName: 'Binance Smart Chain',
                nativeCurrency: {
                    name: 'BNB',
                    symbol: 'BNB',
                    decimals: 18
                },
                rpcUrls: ['https://nodes.pancakeswap.com/'],
                blockExplorerUrls: ['https://bscscan.com/']
            }
        ])
        _chainId = await ethereum.request({method: 'eth_chainId'})
        console.log('chainId2=', _chainId);
        if (_chainId !== chainId) {
            throw Error('Error exchange chain node')
        }
    }
    console.log('eth_requestAccounts==');
    const accounts = await ethereum.request({ method: 'eth_requestAccounts' });
    // address = ethereum.selectedAddress
    console.log('aa=', accounts, ethereum.selectedAddress);
    if (accounts) {
        state.address = accounts[0]
        state.connected = true
        state.connectType = 'metamask'
        listeners.map(fn => fn())
    }
    return address
}

function isMetamask() {
    return !window.Bitpie && typeof window.ethereum !== 'undefined' && window.ethereum.isMetaMask
    // return __DEBUG__ && typeof window.ethereum !== 'undefined' && window.ethereum.isMetaMask
}


async function connect(create) {
    // 24b861d722036a724d8918051be848ab
    if (!__DAPP__) {
        return
    }

    if (isMetamask()) {
        await connectMetamask()
        return
    }


    window.connector = connector
    if (!connector.connected) {
        // console.log('connection not found=', create)
        // console.log(connector);
        if (create) {
            // if (connector.session) {
            //     console.log('kill=');
            //     //await connector.killSession()
            // }
            // console.log('create');
            await connector.createSession({chainId: 0x38});
        }
    } else {
        const { connected, accounts, peerMeta } = connector;
        console.log('connected cache=', connected, accounts, peerMeta)
        // connector.killSession()
        if (accounts) {
            state.address = accounts[0]
            state.connected = true
            state.connectType = 'connect'
            listeners.map(fn => fn())
        } else {
            // connector.killSession()
            // connector.connected = false
        }

    }

}

async function getAddress() {
    return state.address
}

async function sign(url, cancelReact) {
    if (state.connectType === 'http') {
        return '&token=' + state.token
    }

    var msg = 'time' + (Math.floor(Date.now()/1000) + 60*30)
    var address = state.address

    if (state.connectType === 'metamask') {
        let method = 'eth_sign'
        let data
        if (window.bitkeep) {
            data = msg
        } else if (window.Bitpie) {
            method = 'personal_sign'
            // data = msg
            // data = 'login'
            data = web3.utils.keccak256('\x19Ethereum Signed Message:\n' + msg.length + msg)
        } else {
            data = web3.utils.keccak256('\x19Ethereum Signed Message:\n' + msg.length + msg)
        }
        var s
        try {
            var _msg = localStorage.getItem('msg')
            var _sign = localStorage.getItem('sign')
            if (_msg && _sign) {
                var t = _msg.replace('time', '') * 1
                if (t > Date.now()/1000) {
                    console.log('签名未过期');
                    msg = _msg
                    s = _sign
                }
            }
            if (!s) {
                console.log('request=', method, address, data)
                s = await ethereum.request({ method: method, params: [address, data] });
                localStorage.setItem('msg', msg)
                localStorage.setItem('sign', s)
            }
            // s = await ethereum.request({ method: 'personal_sign', params: [ethereum.selectedAddress, 'login'] }).then(function(res){console.log('sign=',res)});
        } catch (e) {
            console.log("cancelReact", cancelReact)
            if(cancelReact){
                state.loaded = false;
            }
            throw Error('sign error')
        }
        let params =  (url.indexOf("?") === -1? "?":"&")+ `address=${state.address}&msg=${msg}&sign=${s}`;
        console.log(params);
        return params
    } else if (state.connectType === 'connect') {
        console.log('request sign msg', address, msg);
        const s = await connector.signMessage([address, msg])
        console.log('sign result==', s)
        return `&address=${state.address}&msg=${msg}&sign=${s}`;
    } else if (state.connectType === 'http') {
        return ''
    } else {
        throw Error('no connect wallet')
    }
}

async function transfer(contractAddress, toAddr, amount, decimal) {

    var selfAddress = await getAddress()
    var ethBalance = await web3.eth.getBalance(selfAddress)
    ethBalance = (ethBalance/(10**decimal)).toFixed(8) * 1
    console.log('eth balance=', ethBalance);
    if (ethBalance < 0.0005) {
        Toast(t("tips.insufficient"))
        throw Error('No Insufficient Amount')
    }

    var wei = '0x' + (amount*(10**decimal)).toString(16)
    const balance = await balanceOf(contractAddress, selfAddress, decimal)
    // console.log('balance=', balance);
    if (amount > balance) {
        Toast(t("tips.insufficient"))
        throw Error('No Insufficient Amount')
    }

    const contract = new web3.eth.Contract(abi, contractAddress)
    var fn = contract.methods.transfer(toAddr, wei)
    return request(fn, contractAddress)
}

async function balanceOf(contractAddress, address, decimal) {
    const contract = new web3.eth.Contract(abi, contractAddress)
    var balance = await contract.methods.balanceOf(address).call()
    console.log('balance=', balance);
    balance = (balance/(10**decimal)).toFixed(2)
    return balance
}

async function request(fn, contractAddress) {
    var data = fn.encodeABI()
    var fromAddr = await getAddress()
    var gas = await fn.estimateGas({
        "from": fromAddr,
    })

    const transactionParameters = {
        // nonce: '0x00', // ignored by MetaMask
        // gasPrice: '0x09184e72a000', // customizable by user during MetaMask confirmation.
        // gas: '0x2710', // customizable by user during MetaMask confirmation.
        gas: `${gas}`,
        to: contractAddress, // Required except during contract publications.
        from: fromAddr, // must match user's active address.
        value: '0x00', // Only required to send ether to the recipient from the initiating external account.
        data: data, // Optional, but used for defining smart contract creation and interaction.
        // chainId: '128', // Used to prevent transaction reuse across blockchains. Auto-filled by MetaMask.
    };

    var txHash

    if (state.connectType === 'metamask') {
        txHash = await ethereum.request({
            method: 'eth_sendTransaction',
            params: [transactionParameters],
        });
        return txHash
    } else if (state.connectType === 'connect') {
        txHash = await connector.sendTransaction({
            gas: `${gas}`,
            to: contractAddress, // Required except during contract publications.
            from: fromAddr, // must match user's active address.
            value: '0x00', // Only required to send ether to the recipient from the initiating external account.
            data: data,
            chainId: 0x38,
        })
    }

    console.log('submit txHash=', txHash);

    return txHash
}

async function watch(txid) {
    return new Promise(resolve => {
        var timer = setInterval(async () => {
            var tx = await web3.eth.getTransaction(txid)
            console.log('tx===', tx);
            if (tx && tx.blockNumber > 0) {
                clearInterval(timer)
                resolve(true)
            }
        }, 2000)
    })
}

export {
    state,
    getAddress,
    transfer,
    sign,
    connect,
    disconnect,
    addConnectListener,
    setDappLocate
}

